/**
 * 事件管理器
 */

export default class _Event {
    private subscribe:{} = {};
    private m_emit_reference_count:number = 0;
    /**
     * @description add listener
     * @public
     * @param name  name listener
     * @param func function for call
     * @param target unxubscribe function
     */

    public on(name,func, target?){
        if(!this.subscribe[name]){ this.subscribe[name]=[] }
        this.subscribe[name].push({func:func,del:false, target:target});
        return() =>{
            this.off(name,func);
        }
    }
    /**
     * @description like on but only call once
     * @public
     * @param name  name listener
     * @param func function for call
     */
    public once(name, func, target?){
        let unsubscribe = undefined;
        unsubscribe = this.on(name, (...args: any[]) => {
            func.apply(target, args);
            unsubscribe();
        }, target);
        return unsubscribe;
    }
    /**
     * @description dispatch event
     * @public
     * @param name  name listener
     * @param func function for call
     */
    public emit(name, ...args){
        ++this.m_emit_reference_count;
        if(this.subscribe[name]){
            this.subscribe[name].forEach((item)=>{
                if(!item.del && item.func){
                    item.func.apply(item.target, args);
                }
            });
        }
        --this.m_emit_reference_count;
        return
    }
    /**
     * @description remove listener
     * @public
     * @param name  name listener
     * @param func function for call
     */
    public off(name, func){
        if(this.subscribe[name]){
            if(func){
                this.subscribe[name].forEach((item)=>{
                    if(item.func === func){
                        item.del = true;
                    }
                });
            }else{
                this.subscribe[name].forEach(item =>{
                    item.del = true
                })
            }           
        }
        if(this.m_emit_reference_count === 0){
            this.clear()
        }
    }
    /**
     * @description remove all listener
     * @public
     */
    public clear(){
        for(let name in this.subscribe){
            this.subscribe[name]=this.subscribe[name].filter(item => !item.del);
        }
    }
}
